#pragma once

#include <iostream>
#include <queue>
#include <pthread.h>
#include "LockGuard.hpp"

const int gDefaultCap = 5;


template <class T>
class BlockQueue
{
private:
    bool isQueueEmpty()
    {
        return _bq.size() == 0;
    }

    bool isQueueFull()
    {
        return _bq.size() == _capacity;
    }

public:
    BlockQueue(int capacity = gDefaultCap)
        :_capacity(capacity)
    {
        pthread_mutex_init(&_mtx, nullptr);
        pthread_cond_init(&_Empty, nullptr);
        pthread_cond_init(&_Full, nullptr);
    }

    void push(const T& in)          //生产者
    {
        // pthread_mutex_lock(&_mtx);

        // //1.先检测当前的临界资源是否满足访问条件
        // //pthread_cond_wait当前是在临界区！而且是持有锁的
        // //pthread_cond_wait的第二个参数是锁，当成功调用wait后，传入的锁，会被自动释放！
        // //从哪里阻塞挂起，就从哪里唤醒
        // //当被唤醒的时候，pthread_cond_wait会自动帮助线程获取锁
        // //pthread_cond_wait:是一个函数，是函数就有调用失败的可能
        // //pthread_cond_wait:可能存在伪唤醒的情况
        // while (isQueueFull())//所以，使用while而不是if，就能100%确定资源是就绪的
        // {
        //     pthread_cond_wait(&_Full, &_mtx);
        // }

        // //2.访问临界资源
        // _bq.push(in);

        // pthread_cond_signal(&_Empty);
        // pthread_mutex_unlock(&_mtx);


        LockGuard lockguard(&_mtx);//自动调用构造函数
        while (isQueueFull())//所以，使用while而不是if，就能100%确定资源是就绪的
        {
            pthread_cond_wait(&_Full, &_mtx);
        }

        //2.访问临界资源
        _bq.push(in);

        pthread_cond_signal(&_Empty);
    }//自动调用LockGuard析构函数

    void pop(T* out)                //消费者
    {
        LockGuard lockguard(&_mtx);
        //pthread_mutex_lock(&_mtx);

        while (isQueueEmpty())
        {
            pthread_cond_wait(&_Empty, &_mtx);
        }

        *out = _bq.front();
        _bq.pop();

        pthread_cond_signal(&_Full);
        //pthread_mutex_unlock(&_mtx);
    }

    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mtx);
        pthread_cond_destroy(&_Empty);
        pthread_cond_destroy(&_Full);
    }

private:
    std::queue<T> _bq;          //阻塞队列
    int _capacity;              //容量上限
    pthread_mutex_t _mtx;       //通过互斥锁保证队列安全
    pthread_cond_t _Empty;    //用来表示bq是否为 空 的条件
    pthread_cond_t _Full;     //用来表示bq是否为 满 的条件
};
